const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'

class MyPromise {
    constructor(executor) {
        try {
            executor(this.resolve, this.reject)
        } catch (e) {
            this.reject(e)
        }

    }

    status = PENDING

    value = undefined
    reason = undefined

    successCallback = []
    rejectCallback = []

    resolve = value => {
        // ======新增逻辑======
        // 如果 value 是一个Mypromise，那我们的库中应该也要实现一个递归解析
        if (value instanceof MyPromise) {
            return value.then(resolve, reject)
        }
        // 更新状态
        if (this.status !== PENDING) return
        this.status = FULFILLED
        // 保存成功的值
        this.value = value

        // 将存下来的回调函数调用
        // 写法1
        // while(this.successCallback.length) this.successCallback.shift()(this.value)
        // 写法2
        this.successCallback.forEach(fn => fn())
    }

    reject = reason => {
        // 更新状态
        if (this.status !== PENDING) return
        this.status = REJECTED
        // 保存失败的理由
        this.reason = reason

        // 将存下来的回调函数调用
        // 写法1
        // while(this rejectCallback.length) this rejectCallback.shift()(this.reason)
        // 写法2
        this.rejectCallback.forEach(fn => fn())
    }


    then = (successCallback, rejectCallback) => {
        // 成功和失败的回调是可选参数，没填的时候直接返回一个箭头函数返回值
        successCallback = successCallback ? successCallback : value => value
        rejectCallback = rejectCallback ? rejectCallback : reason => {
            throw reason
        }

        // 返回一个Mypromise对象
        let returnMyPromise = new MyPromise((resolve, reject) => {
            if (this.status === FULFILLED) { //状态成功后处理回调
                // 由于returnMyPromise在new MyPromise未执行完前是无法拿到的，利用setTimeout将其改为异步
                // 官方规范中是利用MutationObserver的微任务机制完成的
                setTimeout(() => {
                    try {
                        const successReturn = successCallback(this.value)
                        resolveMyPromise(returnMyPromise, successReturn, resolve, reject)
                    } catch (error) {
                        reject(error)
                    }
                }, 0)

            } else if (this.status === REJECTED) {
                setTimeout(() => {
                    try {
                        const rejectReturn = rejectCallback(this.reason)
                        resolveMyPromise(returnMyPromise, rejectReturn, resolve, reject)
                    } catch (error) {
                        reject(error)
                    }
                }, 0)
            } else { //状态未成功时把回调函数保存起来
                this.successCallback.push(() => {
                    setTimeout(() => {
                        try {
                            const successReturn = successCallback(this.value)
                            resolveMyPromise(returnMyPromise, successReturn, resolve, reject)
                        } catch (error) {
                            reject(error)
                        }
                    }, 0)
                })
                this.rejectCallback.push(() => {
                    setTimeout(() => {
                        try {
                            const rejectReturn = rejectCallback(this.reason)
                            resolveMyPromise(returnMyPromise, rejectReturn, resolve, reject)
                        } catch (error) {
                            reject(error)
                        }
                    }, 0)
                })
            }
        })

        return returnMyPromise

    }

    /**
     * MyPromise.all()可以将多个MyPromise实例包装成一个新的MyPromise实例
     * 输入的所有Mypromise的resolve回调的结果是一个数组
     * 等待所有都完成（或第一个失败）
     * @param {[MyPromise]} array
     * @return {MyPromise}
     */
    static all(array) {
        // 判断传入的参数是否数组
        if (!Array.isArray(array)) {
            const type = typeof array;
            return new TypeError(`TypeError: ${type} ${values} is not iterable`)
        }
        let result = []
        let index = 0
        return new MyPromise((resolve, reject) => {
            const addData = (key, value) => {
                result[key] = value
                index++
                if (index === array.lenght) {
                    resolve(result)
                }
            }
            for (let i = 0; i < array.length; i++) {
                const current = array[i];
                if (current instanceof MyPromise) {
                    current.then(value => addData(i, value), reason => reject(reason))
                } else {
                    addData(i, array[i])
                }
            }
        })
    }

    /**
     * MyPromise.race()处理多个请求，采取最快的
     * @param {[MyPromise]} array
     * @return {MyPromise}
     */
    static race(array) {
        // 判断传入的参数是否数组
        if (!Array.isArray(array)) {
            const type = typeof array;
            return new TypeError(`TypeError: ${type} ${values} is not iterable`)
        }
        return new MyPromise((resolve, reject) => {
            //异步的原因，for循环就是一起执行所有Mypromise
            for (let i = 0; i < array.length; i++) {
                let val = array[i]
                if (val && typeof val.then === 'function') {
                    val.then(resolve, reject)
                } else {
                    resolve(val)
                }

            }
        })
    }

    /**
     * MyPromise.resolve()方法的作用是将给定的的值转换成MyPromise对象
     * @param {object} value
     * @return {MyPromise}
     */
    static resolve(value) {
        if (value instanceof MyPromise) return value
        return new MyPromise(resolve => resolve(value))
    }

    /**
     * resolveMyPromise()判断回调的对象是MyPromise还是普通值
     * @param {MyPromise} returnMyPromise
     * @param {object} successReturn
     * @param {Function} resolve
     * @param {Function} reject
     * @return {object}
     */
    resolveMyPromise = (returnMyPromise, successReturn, resolve, reject) => {
        // 如果成功后的回调是自己，则报错
        if (successReturn === returnMyPromise) {
            reject(new TypeError('Chaining cycle detected for Mypromise #<MyPromise>'))
        }
        if (successReturn instanceof MyPromise) { //返回的Mypromise对象则调用它的then
            successReturn.then(resolve, reject)
        } else { // 返回是普通值则直接处理
            resolve(successReturn)
        }

    }


}